<script setup>
import { Graph } from '@antv/x6'
import { markRaw, nextTick, onMounted, reactive, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { useStore } from "../stores/index";
import { Selection } from '@antv/x6-plugin-selection'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { Stencil } from '@antv/x6-plugin-stencil'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Transform } from '@antv/x6-plugin-transform'
import { Export } from '@antv/x6-plugin-export'
import { ElMessage } from 'element-plus';
import sumMain from "../views/sum/main.vue";
import sumAttr from "../views/sum/attr.vue";
import Menu from "../views/Menu.vue";
import icons from "../components/icons/icons";

const router = useRouter()
const store = useStore()


const amplify = [
    {
        tagName: 'path',
        attrs: {
            stroke: 'transparent',
            strokeWidth: 300,
        },
    },
]
const downArrow = {
    transform: 'scale(0.015) translate(-450,-850)',
    d: 'M104.704 338.752a64 64 0 0 1 90.496 0l316.8 316.8 316.8-316.8a64 64 0 0 1 90.496 90.496L557.248 791.296a64 64 0 0 1-90.496 0L104.704 429.248a64 64 0 0 1 0-90.496z',
    magnet: true,
    style: {
        // visibility: 'hidden',
    }
}
const defaultInput = {
    group: 'left',
    markup: amplify,
    attrs: {
        path: downArrow,
    },
}
const pi = {
    default: defaultInput,
    cheng: {
        ...defaultInput,
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#f44336' },
            text: {
                text: '×',
            },
        },
    },
    chu: {
        ...defaultInput,
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#2196f3' },
            text: {
                text: '÷'
            }
        },
    },
    jia: {
        ...defaultInput,
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#f44336' },
            text: {
                text: '+',
            },
        },
    },
    jian: {
        ...defaultInput,
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#2196f3' },
            text: {
                text: '-'
            }
        },
        label: {
            position: {
                args: {
                    x: 9
                }
            }
        }
    },
    jiac: {
        ...defaultInput,
        group: 'ellipse',
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#f44336' },
            text: {
                text: '+'
            }
        },
    },
    jianc: {
        ...defaultInput,
        group: 'ellipse',
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#2196f3' },
            text: {
                text: '-',
            }
        },
    },
    deng: {
        ...defaultInput,
        type: 'chu',
        group: 'right',
        attrs: {
            path: downArrow,
            // path: { ...downArrow, fill: '#4caf50' },
            text: {
                // text: '='
            }
        },
    },
}
const ports = {
    groups: {
        left: {
            position: {
                args: {
                    angle: -90,
                },
            },
            label: {
                position: {
                    name: 'right',
                    args: {
                        x: 7
                    }
                }
            }
        },
        right: {
            position: {
                name: 'right',
                args: {
                    dx: 8,
                    angle: -90,
                }
            },
            label: {
                position: {
                    args: {
                        y: -2
                    }
                }
            }
        },
        ellipse: {
            position: {
                name: 'ellipse',
                args: {
                    start: -90,
                    compensateRotate: true
                }
            },
            label: {
                position: {
                    name: 'right',
                    args: {
                        x: 7
                    }
                }
            }
        },
    },
}

function list2port(e, f) {
    // let arr = e.split('|')
    //   .map(i => i ? i.split('') : '')
    const dSet = {
        'rect': {
            '+': pi.jia,
            '-': pi.jian,
            '=': pi.chu,
        },
        'circle': {
            '+': pi.jiac,
            '-': pi.jianc,
            '=': pi.chu,
        },
    }
    let arr = e.split('').toReversed().map(i => dSet[f][i])
    return arr
}


const data = {
    nodes: [
        {
            id: 'node1',
            shape: 'rect',
            x: 660,
            y: 180,
            width: 50,
            height: 20,
            label: '1',
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                    rx: 10,
                    ry: 10,
                },
            },
            ports: {
                ...ports,
                items: [
                    {
                        ...pi.deng,
                        id: 'output'
                    }
                ]
            }
        },
        {
            id: 'node2',
            shape: 'rect',
            x: 860,
            y: 180,
            width: 50,
            height: 20,
            label: '2',
            attrs: {
                body: {
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                    fill: '#fff',
                    rx: 10,
                    ry: 10,
                },
            },
            ports: {
                ...ports,
                items: [
                    {
                        ...pi.default,
                        id: 'input'
                    }
                ]
            }
        },
    ],
}

// ports: {
//                 ...ports,
//         items: [
//             {
//                 ...pi.default,
//                 id: 'input',
//                 attrs: {
//                     path: {
//                         ...pi.default.attrs.path,
//                         style: {
//                             visibility: 'hidden'
//                         }
//                     }
//                 },
//             }
//         ]
// }





const activeName = ref(0)
const con = reactive({
    data: {
        title: '加法',
        content: `对输入执行加法或减法。请指定下列选项之一:a)字符向量，其中包含+或-表示每个输入端口，包含|表示端口之间的分隔符(例如 +- ++)b)标量，>=1，指定要求和的输入端口的数量。当只有一个输入端口时，在所有维度或指定维度上对元素执行加法或减法。`
    },
    page: [
        {
            name: '主要',
            component: markRaw(sumMain),
            data: {
                type: '',
                list: ''
            }
        },
        {
            name: '信号属性',
            component: markRaw(sumAttr),
            data: {
                type: '',
                list: ''
            }
        }
    ]
})
const actNode = ref()





let setEvent = reactive({
    con: 0,
    help: 0,
    fanhui: 0
})
function confirm() {
    setEvent.con++
}
function help() {
    setEvent.help++
}
const stencilWidth = 300



onMounted(() => {
    const graph = new Graph({
        container: document.getElementById('container'),
        autoResize: true,
        connecting: {
            snap: {
                radius: 15,
            },
            allowLoop: false,
            allowNode: false,
            allowMulti: false,
            // allowPort: false,
            // highlight: true,
            connector: {
                name: 'jumpover',
                args: {
                    type: 'cubic',
                    size: 7,
                }
            },
            router: {
                name: 'manhattan',
                args: {
                    padding: {
                        left: 20,
                        // right: 60
                    },
                    step: 20,
                    startDirections: ['right'],
                }
            },
            connectionPoint: 'anchor',
            anchor: 'left',
        },
        grid: {
            visible: true,
            type: "mesh",
            size: 20, // 网格大小 px
            color: "rgb(246,246,246)",
        },
        highlighting: {
            magnetAvailable: {
                name: 'stroke',
                args: {
                    padding: 4,
                    attrs: {
                        'stroke-width': 2,
                        stroke: '#FEB663',
                    },
                },
            },
        },
        translating: {
            restrict: true,
        },
        mousewheel: {
            enabled: true,
            modifiers: ['ctrl', 'meta'],
        },
        panning: {
            enabled: true,
            modifiers: ['ctrl', 'meta'],
        },
        // width: '100%',
        // height: '100%',
        background: {
            color: '#F2F7FA',
        },
    })
    graph.fromJSON(data) // 渲染元素
    // graph.centerContent() // 居中显示
    graph.use(
        new Selection({
            enabled: true,
            multiple: true,
            rubberband: true,
            movable: true,
            showNodeSelectionBox: true,
            // showEdgeSelectionBox: true,
            // pointerEvents: 'none'
        }),
    )
    graph.use(
        new Keyboard({
            enabled: true,
            global: true
        }),
    )
    graph.use(
        new Clipboard({
            enabled: true,
        }),
    )
    graph.use(
        new Snapline({
            enabled: true,
        }),
    )
    graph.use(
        new Transform({
            resizing: {
                enabled: true,
                preserveAspectRatio: true,
                allowReverse: false,
                minWidth: 60,
                minHeight: 60
            },
            rotating: {
                enabled: true,
            },
        }),
    )
    graph.use(new Export())
    // const stencil = new Stencil({
    //     title: '全部',
    //     target: graph,
    //     // search: true,
    //     placeholder: '请输入控件名称',
    //     notFoundText: '暂无匹配控件',
    //     search: (cell, keyword, groupName, stencil) => {
    //         if (keyword) {
    //             return cell.attr('text/text').includes(keyword)
    //         }
    //         return true
    //     },
    //     collapsable: true,
    //     stencilGraphWidth: stencilWidth,
    //     stencilGraphHeight: 0,
    //     stencilGraphPadding: [],
    //     layoutOptions: {
    //         rowHeight: 150
    //     },
    //     groups: [
    //         {
    //             name: '控件',
    //         },
    //         {
    //             name: '控件2',
    //         },
    //     ],
    // })
    // const stencilContainer = document.getElementById('stencilContainer')
    // stencilContainer.appendChild(stencil.container)
    // stencil.load([data.nodes[0], data.nodes[1]], '控件')
    // stencil.load([data.nodes[2]], '控件2')






    if (store.childrenData) {
        console.log('初始化子组件', store.childrenData);
        graph.resetCells(store.childrenData)
    }










    // 绑定复制粘贴事件
    graph.bindKey('ctrl+c', () => {
        const cells = graph.getSelectedCells()
        if (cells.length) {
            graph.copy(cells)
        }
        return false
    })
    graph.bindKey('ctrl+v', () => {
        if (!graph.isClipboardEmpty()) {
            const cells = graph.paste({ offset: 32 })
            graph.cleanSelection()
            graph.select(cells)
        }
        return false
    })
    // 监听连线完成事件
    graph.on('edge:connected', (
        {
            isNew,
            edge,
            previousCell: pCell,
            currentCell: cCell,
            previousPort: ppix,
            currentPort: cpix,
            view: {
                routePoints
            }
        }
    ) => {
        if (isNew) {
            // 对新创建的边进行插入数据库等持久化操作




            // 获取源节点和源节点连接桩的id
            ppix = edge.getSourcePortId()
            pCell = edge.getSourceCell()
        }
        // console.log(isNew, ppix, cpix);
        let pp = ppix ? pCell.getPort(ppix) : null
        let cp = cpix ? cCell.getPort(cpix) : null
        let sp = edge.source.port ? edge.getSourceCell().getPort(edge.source.port) : null
        let tp = edge.target.port ? edge.getTargetCell().getPort(edge.target.port) : null
        // console.log(edge, pp, cp);
        console.log(pCell, cCell);

        // pp: 连接操作起始状态端，cp: 连接操作终止状态端
        // sp: 连线起始端，tp: 连线终点端

        // 非法移动起点
        let pIllegal = pp?.id != tp?.id && cp?.id == sp?.id
        // 非法移动终点
        let cIllegal = pp?.id != sp?.id && cp?.id == tp?.id
        if ((pIllegal || cIllegal) && pp) {
            pCell.setPortProp(ppix, 'attrs/path', {
                visibility: 'visible'
            })
        }


        // 禁止连接输入输出端非法连接
        // console.log(pp, sp, cp, tp);
        if (sp && sp?.type != 'chu') {
            edge.remove()
            ElMessage.warning('不能从输入端连接！')
            return
        }
        if (tp?.type == 'chu') {
            edge.remove()
            ElMessage.warning('不能连接输出端！')
            return
        }



        // 连线生成后



        // 连接线一端以上悬空即变为红色虚线
        if (sp && tp) {
            edge.attr({
                line: {
                    stroke: '#000',
                    strokeDasharray: 0
                }
            })
        } else {
            edge.attr({
                line: {
                    stroke: '#f44336',
                    strokeDasharray: '10, 10'
                }
            })
        }



        // 控制箭头的显示隐藏
        if (pp) pCell.setPortProp(ppix, 'attrs/path', {
            visibility: !isNew ? 'visible' : 'hidden'
        })
        if (cp) cCell.setPortProp(cpix, 'attrs/path', {
            visibility: 'hidden'
        })






        // if (sp && tp) {
        // edge.setVertices(routePoints)
        // }






        // 设置终点箭头形态
        edge.attr({
            line: {
                targetMarker: {
                    name: 'classic',
                    size: 16,
                    offset: 4
                    // tagName: 'path',
                    // // fill: 'yellow', // 使用自定义填充色
                    // // stroke: 'green', // 使用自定义边框色
                    // strokeWidth: 0,
                    // d: 'M .5 -8 16 0 .5 8 4 1 -14 1 -14 -1 4 -1 Z',
                },
            },
        })
    })
    graph.on('edge:added', ({ edge }) => {

        // 为新生成的线添加路径点

    })
    graph.on('edge:changed', ({ edge, edge: { target, source: { port: ppix } } }) => {
        // edge.prop('vertices', vertices)
        if (!target.port) {
            // console.log(edge, edge.prop());
            let pCell = edge.getSourceCell()
            let pp = ppix ? pCell.getPort(ppix) : null
            if (pp) pCell.setPortProp(ppix, 'attrs/path', {
                visibility: 'hidden'
            })
            edge.attr({
                line: {
                    stroke: '#f44336',
                    strokeDasharray: '10, 10'
                }
            })
        }
    })
    graph.on('edge:removed', ({
        edge: {
            source: {
                cell: pcix,
                port: ppix
            },
            target: {
                cell: ccix,
                port: cpix
            }
        }
    }) => {
        let pCell = graph.getCellById(pcix)
        let cCell = graph.getCellById(ccix)
        let pp = ppix ? pCell.getPort(ppix) : null
        let cp = cpix ? cCell.getPort(cpix) : null
        // console.log(pCell, cCell, pp, cp);
        // 连线销毁时恢复箭头
        if (pp) pCell.setPortProp(ppix, 'attrs/path', {
            visibility: 'visible'
        })
        if (cp) cCell.setPortProp(cpix, 'attrs/path', {
            visibility: 'visible'
        })
    })
    // 移入节点添加工具
    graph.on('cell:mouseenter', ({ cell }) => {
        let args
        if (!cell.isNode()) {
            cell.addTools([
                // {
                //   name: 'vertices',
                //   args: {
                //     // addable: false,
                //     removable: false
                //   }
                // },
                {
                    name: 'segments',
                    args: {
                        snapRadius: 20,
                        attrs: {
                            fill: '#8f8f8f',
                        },
                    },
                },
                {
                    name: 'source-arrowhead',
                    args: {
                        attrs: {
                            d: 'M -2.5 -10 17.5 0 -2.5 10 Z',
                            fill: '#f44336',
                            // d: 'M .5 -8 16 0 .5 8 4 1 -14 1 -14 -1 4 -1 Z',
                            // 'stroke-width': 0,
                        }
                    }
                },
                {
                    name: 'target-arrowhead',
                    args: {
                        attrs: {
                            d: 'M -7.5 -10 12.5 0 -7.5 10 Z',
                            fill: '#f44336',
                            // d: 'M .5 -8 16 0 .5 8 4 1 -14 1 -14 -1 4 -1 Z',
                            // 'stroke-width': 0,
                        }
                    }
                },
                {
                    name: 'button-remove',
                    args: args
                }
            ])
        }
    })

    // graph.on("node:mousedown", (e) => {
    //   const connectedEdges = graph.getConnectedEdges(e.cell)
    //   connectedEdges.forEach(edge => {
    //     edge.setVertices([])
    //   })
    // })
    // graph.on("node:mouseup", (e) => {
    //   const connectedEdges = graph.getConnectedEdges(e.cell)
    //   connectedEdges.forEach(edge => {
    //     edge.setVertices(graph.findViewByCell(edge).routePoints)
    //   })
    // })

    // 移除节点去除工具
    graph.on('cell:mouseleave', ({ cell }) => {
        cell.removeTools()
    })
    // 双击进行属性改动
    graph.on('node:dblclick', ({ cell: { id, shape, port } }) => {
        actNode.value = id
        // let cell = graph.getCellById(id)
        // console.log(cell, shape, port);
        let changeObj = {
            // node: () => {
            //     let data = con.page[activeName.value].data
            //     data.type = shape
            //     data.list = port.ports.map(i => i.attrs.text.text).join('')
            //     con.is = true
            // },
            node1: () => {
                let data = con.page[activeName.value].data
                data.type = shape
                data.list = port.ports.map(i => i.attrs.text.text).join('')
                con.is = true
            },
            node2: () => {
                // console.log(svg);

            }
        }



        changeObj[id]()
    })
    // 右键单击呼出菜单
    graph.on('cell:contextmenu', ({ cell, e, x, y }) => {
        nodeMenu.cell = cell
        menu.data = nodeMenu
        console.log(menu.data);
        huchu(x, y)
    })
    graph.on('cell:click', () => {
        let domM = document.getElementById('menu')
        if (domM) menu.is = false
    })
    graph.on('blank:contextmenu', ({ e, x, y }) => {
        menu.data = blankMenu
        huchu(x, y)
    })
    graph.on('blank:click', () => {
        let domM = document.getElementById('menu')
        if (domM) menu.is = false
    })
    // 监听确认按钮
    watch(() => setEvent.con, () => {
        let cell = graph.getCellById(actNode.value)
        let data = con.page[activeName.value].data
        // console.log(cell.prop(), data);



        let { shape } = cell.prop()
        if (data.type != shape) {
            let _set = {
                ...cell.prop(),
                shape: data.type,
                ports: { ...ports, items: [] }
            }
            // console.log(cell.prop(), _set);
            cell.remove()
            cell = graph.addNode(_set)
        }
        let _arr = list2port(data.list, data.type)
        // console.log(_arr);
        cell.prop('ports/items', _arr)
        // console.log(cell.prop());

        con.is = false
    })
    // 监听帮助按钮
    watch(() => setEvent.help, () => {
        console.log('help');
    })
    watch(() => setEvent.fanhui, () => {
        console.log('help');
        fanhui()
    })





    graph.addEdge({
        // shape: 'edge',
        source: { cell: 'node1', port: 'output' },
        target: { cell: 'node2', port: 'input' },
        attrs: {
            line: {
                targetMarker: {
                    name: 'classic',
                    size: 16,
                    offset: 0
                },
            },
        },
    })
    // graph.getCellById('node1').portProp('output', 'attrs/path/style/visibility', 'hidden')
    // graph.getCellById('node2').portProp('input', 'attrs/path/style/visibility', 'hidden')
    function fanhui() {
        graph.toPNG((e) => {
            console.log(e);
            // console.log(graph.getCells());
            store.childrenData = graph.getCells()
            store.svg = e
            router.push('/')
        }, {
            padding: {
                left: 16,
                right: 8,
                top: 10,
                bottom: 10
            }
        })
    }
})

function huchu(x, y) {
    menu.x = x
    menu.y = y
    menu.is = true
}
let nodeMenu = [
    {
        name: '删除节点',
        icon: icons.delete,
        fn: () => {
            let cell = nodeMenu.cell
            console.log('删除节点', cell.prop());
            cell.remove()
        }
    }
]
let blankMenu = [
    {
        name: '功能按钮1',
        icon: icons.copy,
        fn: () => {
            console.log('功能按钮1');
        }
    },
    {
        name: '功能按钮2',
        icon: icons.add,
        fn: () => {
            console.log('功能按钮2');
        }
    },
    {
        name: '功能按钮3',
        icon: icons.delete,
        fn: () => {
            console.log('功能按钮3');
        }
    },
]
const menu = reactive({
    is: false,
    x: 0,
    y: 0,
    data: null
})


// import Ripple from "./views/Ripple.vue";
</script>

<template>
    <!-- <RouterView /> -->
    <div id="container"></div>
    <!-- <div id="stencilContainer"></div> -->
    <div id="menu" v-if="menu.is">
        <Menu :settings="menu" />
    </div>
    <!-- <div v-html="svg"></div> -->
    <!-- <Ripple /> -->
    <div @click="setEvent.fanhui++" class="fanhui">
        返回
    </div>




    <el-dialog v-model="con.is" draggable :title="con.data?.title" width="400" :close-on-click-modal="false">
        <div class="title">{{ con.data?.title }}</div>
        <div class="content">{{ con.data?.content }}</div>


        <el-tabs v-model="activeName" type="card" class="tabs">
            <template v-for="im, ix in con.page" :key="ix">
                <el-tab-pane :label="im.name" :name="ix">
                    <component :is="im.component" :data="im.data" />
                </el-tab-pane>
            </template>
        </el-tabs>
        <template #footer>
            <div class="dialog-footer">
                <el-button @click="confirm">确认</el-button>
                <el-button @click="con.is = false">取消</el-button>
                <el-button @click="help">帮助</el-button>
            </div>
        </template>
    </el-dialog>
</template>

<style scoped>
::-webkit-scrollbar {
    width: 0;
}

#container {
    width: 100vw;
    height: 100vh;
}

#stencilContainer {
    width: v-bind('stencilWidth + "px"');
    height: calc(100vh - 30px);
    margin: 15px;
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
    position: fixed;
    inset: 0;

    &>>>.x6-widget-stencil-group-content {
        padding: 10px 0 50px !important;
    }

    & ::-webkit-scrollbar {
        width: 0;
    }
}

#menu {
    position: fixed;
    left: v-bind("menu.x + 'px'");
    top: v-bind("menu.y + 'px'");

    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
}

>>>.x6-widget-transform-rotate {
    width: 20px;
    height: 20px;
    top: -30px;
    left: calc(50% - 8px);
    cursor: pointer;
    background: url(/rotate.png) center / cover no-repeat;
    border: 0;
    /* top: -365%;
  left: -435%;
  width: 1000px;
  height: 1000px;
  background-color: #feb663;
  clip-path: path("M784.512 230.272v-50.56a32 32 0 1 1 64 0v149.056a32 32 0 0 1-32 32H667.52a32 32 0 1 1 0-64h92.992A320 320 0 1 0 524.8 833.152a320 320 0 0 0 320-320h64a384 384 0 0 1-384 384 384 384 0 0 1-384-384 384 384 0 0 1 643.712-282.88z");
  transform: scale(.02) */
}

>>>.x6-widget-transform {
    border: 2px dashed #feb663;
    margin: -13.5px;
    padding: 11.5px;
}

>>>.x6-widget-selection-inner {
    padding: 18px;
    margin: -20px;
    border-style: dashed;
    box-shadow: rgba(60, 64, 67, 0.3) 0 1px 2px 0, rgba(60, 64, 67, 0.15) 0 2px 6px 2px;
}

>>>.x6-widget-selection-box {
    border: 0;
    box-shadow: none;
}

.x6-graph.x6-graph-pannable {
    cursor: initial;
}

.title {
    position: absolute;
    transform: translate(8px, -12px);
    background-color: #FFF;
}

.content {
    border: 1px solid var(--el-border-color);
    margin: 0 0 12px;
}

.tabs {
    height: 200px;
}

.fanhui {
    position: fixed;
    inset: 30px 50px;
    width: 100px;
    height: 50px;
    background-color: #fcfcfc;
    border-radius: 25px;
    display: flex;
    justify-content: center;
    align-items: center;
    border: 1px solid #feb663;

    &:hover {
        background-color: #FFF;
        cursor: pointer;
    }
}
</style>